package com.wn.ticket.security.backstage;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wn.ticket.common.JwtUtils;
import com.wn.ticket.security.JwtException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author wuqingting
 * @date 2022/8/22
 */
public class BackstageJwtAuthenticationFilter extends OncePerRequestFilter {
    private JwtUtils jwtUtil;
    private AuthenticationFailureHandler authenticationFailureHandler;
    private AdminUserDetailsService oaUserDetailsService;
    private StringRedisTemplate redisTemplate;

    public BackstageJwtAuthenticationFilter(JwtUtils jwtUtil, AuthenticationFailureHandler authenticationFailureHandler, AdminUserDetailsService oaUserDetailsService, StringRedisTemplate redisTemplate) {
        this.jwtUtil = jwtUtil;
        this.authenticationFailureHandler = authenticationFailureHandler;
        this.oaUserDetailsService = oaUserDetailsService;
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request.getRequestURI().equals("/ticket/backstage/captcha")||
                request.getRequestURI().contains("/backstage/img")) {
            filterChain.doFilter(request, response);
            return;
        }
        String token = request.getHeader("token");
        if (token==null){
            authenticationFailureHandler.onAuthenticationFailure(request,response,new JwtException("token为空"));
            return;
        }
        if (!jwtUtil.verifySecretJWT(token)){
            authenticationFailureHandler.onAuthenticationFailure(request,response,new JwtException("token无效"));
            return;
        }
        if (!jwtUtil.verifyTimeJWT(token)){
            authenticationFailureHandler.onAuthenticationFailure(request,response,new JwtException("token已过期"));
            return;
        }
        String account = (String) jwtUtil.getInfo(token, "account");
        //UserDetails userDetails = oaUserDetailsService.loadUserByUsername(account);//根据账号查数据库(原始方法,现使用缓存代替查询数据库)
        String json = (String) redisTemplate.opsForHash().get("admin", account);//从redis拿用户(拿到的为反序列化前的数组对应的json对象)
        UserDetails userDetails = null;
        try {
            byte[] unSerialize=new ObjectMapper().readValue(json, byte[].class);//将json转为反序列化前的数组
            userDetails = (UserDetails) SerializeUtil.unSerialize(unSerialize);//将反序列化数组转换为对象
        } catch (JsonProcessingException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        //验证成功后生成UsernamePasswordAuthenticationToken,,这里密码为null，是因为提供了正确的JWT,实现自动登录
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request,response);

    }
}
